package database.dbObjects;

import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Vector;

import main.Main;
import objects.Exam;


public interface IDBExam extends IDBTask {
	
	public class DBExam extends DBTask {
		
		/*
		 * methods are final for optimization of the code (by the compiler)
		 * it is not possible anymore to inherit it after this declaration 
		 */
		
		public final void init() throws Exception {
			
			createTable();
		}
		
		private final void createTable() throws Exception {
			
			String query = "create table Exam( " +
						   "Name varchar(" + maxLengthName + ") unique not null, " +
						   "Room varchar(" + maxLengthRoom + ") not null, " +
						   "Hours integer not null, " +
						   "Type char(1) not null, " +
						   "Oral boolean not null, " +
						   "foreign key (Name) references Task (Name), " +
						   "primary key (Name) " +
						       "on conflict abort, " +
						   "check ((Hours > 0) and (Hours <= " + maxHours + ")), " +
						   "check (Type in ('T','P','B')));"; // Theory, Practicum or Both
	        
			executeCreation(query);
		}
		
		public final boolean add(String name, String desc, Boolean done, 
				Integer grades, String moreInfo, String room, Integer hours, 
				Character type, Boolean oral) throws Exception {
			
			checkConsistance(name, desc, done, grades, moreInfo, room, hours, type, oral);
			
			boolean success = super.add(name, desc, done, grades, moreInfo);
			
			Vector<Object> v = new Vector<Object>(5);
			v.add(0, name);
			v.add(1, room);
			v.add(2, hours);
			v.add(3, type);
			v.add(4, oral);
			
			return (success && super.add("Exam", v));
		}
		
		public final boolean updateRoom(String name, String newRoom) throws Exception {
			
			checkName(name);
			checkRoom(newRoom);
			
			return super.update("Exam", "Name", name, "Room", newRoom);
		}
		
		public final boolean updateHours(String name, Integer newHours) throws Exception {
			
			checkName(name);
			checkHours(newHours);
			
			return super.update("Exam", "Name", name, "Hours", newHours);
		}
		
		public final boolean updateType(String name, Character newType) throws Exception {
			
			checkName(name);
			checkType(newType);
			
			return super.update("Exam", "Name", name, "Type", newType);
		}
		
		public final boolean updateOral(String name, Boolean oral) throws Exception {
			
			checkName(name);
			checkOral(oral);
			
			return super.update("Exam", "Name", name, "Oral", oral);
		}
		
		public final Exam getExam(String name) throws Exception {
			// Returns the requested object or null if nothing was found
			
			Statement stat = Main.connection.createStatement();
			ResultSet rs = stat.executeQuery("select * from Exam natural join Task " +
											 "where (Exam.Name = '" + name + "');");
			if (rs.next()) {
				Exam e = new Exam(rs.getString("Name"), rs.getString("Description"), 
						rs.getBoolean("Done"), rs.getInt("Grades"), rs.getString("MoreInformation"), 
						rs.getString("Room"), rs.getInt("Hours"), rs.getString("Type"), 
						rs.getBoolean("Oral"));
				rs.close();
				return e;
			}
			rs.close();
			return null;
		}
		
		public final Vector<Exam> getAllExams() throws Exception {
			
			Statement stat = Main.connection.createStatement();
			ResultSet rs = stat.executeQuery("select * from Exam natural join Task;");
			
			Vector<Exam> v = new Vector<Exam>();
			int counter = 0;
			while (rs.next()) {
				v.add(counter, new Exam(rs.getString("Name"), rs.getString("Description"), 
					rs.getBoolean("Done"), rs.getInt("Grades"), rs.getString("MoreInformation"), 
					rs.getString("Room"), rs.getInt("Hours"), rs.getString("Type"), 
					rs.getBoolean("Oral")));
				counter++;
			}
			rs.close();
			return v;
		}
		
		private final void checkConsistance(String name, String desc, Boolean done, 
				Integer grades, String moreInfo, String room, Integer hours, Character type, 
				Boolean oral) throws Exception {
			
			super.checkConsistance(name, desc, done, grades, moreInfo);
			checkRoom(room);
			checkHours(hours);
			checkType(type);
			checkOral(oral);
		}
		
		private final void checkRoom(String room) throws Exception {
			
			if (room == null) { throw (new Exception("Room needed!")); }
			if (room.length() < 1) {
				throw (new Exception("Room has to be at least 1 character long!"));
			}
			if (room.length() > maxLengthRoom) {
				throw (new Exception("Room exceeds maximum length (" +
						maxLengthRoom + " characters)!"));
			}
		}
		
		private final void checkHours(Integer hours) throws Exception {
			
			if (hours == null) { throw (new Exception("Number of hours needed!")); }
			if (hours < 0) {
				throw (new Exception("Number of hours can't be negative!"));
			}
			if (hours > maxHours) {
				throw (new Exception("Number of hours can't be more than " + 
						maxHours + "!"));
			}
		}
		
		private final void checkType(Character type) throws Exception {
			
			if (type == null) { throw (new Exception("Type needed!")); }
			if (!((type == 'T') || (type == 'P') || (type == 'B'))) { 
				throw (new Exception("Type does not exist! Character must be: " +
						"T (theory), P (practice) or B (both)"));
			}
		}
		
		private final void checkOral(Boolean oral) throws Exception {
			
			if (oral == null) { throw (new Exception("Boolean Oral needed!")); }
		}
		
		
		private final int maxLengthRoom = 5;
		private final int maxHours = 4;
		
	}
	
}
